
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#include <arpa/inet.h> 
#include <sys/select.h>
#include <sys/time.h>
#include <net/if.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <linux/if_tun.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <arpa/inet.h> 
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <stdarg.h>

#include <linux/if_tun.h>
#include "pktinfo.h"
#include "udp-client.h"
#include "session-mng.h"
#include "util.h"

#define TEST_SERVER_IP "192.168.2.3"
#define TEST_DPORT   4001
#define TEST_CTLPORT 4002
typedef int (*F_SEND_PKT)(SESSION_ENTRY *sentry,uint8_t *buff,int size);
#define BUFSIZE 2000   
int tap_fd = -1;

int tun_loop_process(SESSION_ENTRY *sentry,F_SEND_PKT send) {
  
  int option;
  
  char if_name[IFNAMSIZ] = "";

  uint16_t nread, nwrite, plength;
  char buffer[BUFSIZE];
  char remote_ip[16] = "";            /* dotted quad IP string */
  int cliserv = -1;    /* must be specified on cmd line */
  unsigned long int tap2net = 0, net2tap = 0;

  

  while(1) {
    int ret;
    fd_set rd_set;

    FD_ZERO(&rd_set);
    FD_SET(tap_fd, &rd_set); 

    ret = select(tap_fd + 1, &rd_set, NULL, NULL, NULL);

    if (ret < 0 && errno == EINTR){
      continue;
    }

    if (ret < 0) {
      perror("select()");
      break;
    }

    if(FD_ISSET(tap_fd, &rd_set)) {
      /* data from tun/tap: just read it and write it to the network */
      

	  nread=read(tap_fd, buffer, BUFSIZE);
	  if (nread < 0)
	  {
		 perror("read()");	
		 break;
	  }
      tap2net++;
      //printf("TAP2NET %lu: Read %d bytes from the tap interface\n", tap2net, nread);

      /* write length + packet */
      //plength = htons(nread);
     // nwrite = cwrite(net_fd, (char *)&plength, sizeof(plength));
     // nwrite = cwrite(net_fd, buffer, nread);
      if (send)
	  	send(sentry,buffer,nread);
      //printf("TAP2NET %lu: Written %d bytes to the network\n", tap2net, nwrite);
    }

  }
  
  return(0);
}


int receive_data_pkt_callback(SESSION_ENTRY *sentry,int portidx,uint8_t *buff,int size)
{
	UDP_CHANNEL_HEADER *u_header = NULL;
	//printf(" %d port,%d bytes\n",portidx,size);
	u_header= (UDP_CHANNEL_HEADER*)buff;
	u_header->idx = ntohll(u_header->idx);
	u_header->size = ntohs(u_header->size);
	u_header->ptkinfo.dstip = ntohl(u_header->ptkinfo.dstip);
	u_header->ptkinfo.srcip = ntohl(u_header->ptkinfo.srcip);
	u_header->ptkinfo.dport = ntohs(u_header->ptkinfo.dport);
	u_header->ptkinfo.sport = ntohs(u_header->ptkinfo.sport);
	process_pkt(sentry->streammng,buff,size);
	return 0;
}

typedef int (*F_SEND_PKT)(SESSION_ENTRY *sentry,uint8_t *buff,int size);
int write_stream_to_session(SESSION_ENTRY *sentry,uint8_t *buff,int size)
{
	return write_session_stream(sentry,buff,size);
}

#if 1
char *g_localip;
int main(int argc,char **argv)
{
	int ret = 0;
	int i = 0;
	int flags = IFF_TUN;
	SESSION_ENTRY *sentry = NULL;
	if (argc < 4)
	{
		printf("useage:ip dport ctlport\n");
		exit(-1);
	}
	char *ip = argv[1];
	//int dport[3] = {1234,2345,3456};
	//int ctlport[3] = {4321,5432,6543};
	g_localip = argv[2];
	int ctlport = 4321;
	init_session();

	/* initialize tun/tap interface */
	if ( (tap_fd = tun_alloc("tun0", flags | IFF_NO_PI)) < 0 ) {
		printf("Error connecting to tun/tap interface tun0!\n");
		return -1;
	}
	printf("Successfully connected to interface tun0\n");
	set_if_addr("tun0",g_localip,"255.255.255.0",NULL);
	system("ifconfig tun0 mtu 1468 up");
	
	sentry = create_session(3,ip,1234,4321);
	if (sentry == 0)
	{
		printf("create session error\n");
		exit(-1);
	}
	printf("begin register_session_datacb\n");
	register_session_datacb(sentry,receive_data_pkt_callback);
	
	start_session(sentry);
	printf("start session successe\n");
	//printf("start session successe\n");
#if 0
	while(1)
	{
#if 0
		for(i = 0;i < 3;i++)
		{
			sprintf(tx_buff,"hello world hello world hello world hello world ",i);
			write_session_by_idx(sentry,i,tx_buff,strlen(tx_buff));
			//write_session_stream(sentry,tx_buff,i);
		}
#endif
		sprintf(tx_buff,"hello world hello world hello world hello world hello world hello world hello world hello world1\n");
		write_session_stream(sentry,tx_buff,strlen(tx_buff));
		sleep(5);
	}
#endif
	tun_loop_process(sentry,write_stream_to_session);
	printf("client exist\n");
	return 0;
}
#else
//test pkt memory
int main ()
{
	uint8_t *ptk = NULL;
	init_pkt_buff(500,100);
	while (1)
	{
		ptk = malloc_pkt_buffer();
		if (ptk == NULL)
		{
			printf("malloc_pkt_buffer failed\n");
			exit(-1);
		}
		
		printf("%p %d\n",ptk,get_free_pkt());
		free_pkt_buffer(ptk);
		usleep(100000);
	}
}
#endif
